#include "MarcoTestState.h"
#include "Graphics.h"
#include "Timer.h"
#include "MyGL.h"
#include "Game.h"
#include "Error.h"
#include <SDL_events.h>
#include <iostream>
#include "AssetManager.h"
#include "StringUtility.h"

//for test
#include "LookWhereYoureGoing.h"
#include "CollisionAvoidance.h"
#include "MathUtility.h"
#include "Wander.h"
#include "Pursue.h"
#include "World.h"

MarcoTestState::MarcoTestState()
{
	m_hash = Engine::Hash(GetName());
}

static bool ls = Engine::TheGame::Instance() ->RegisterGameState(TheMarcoTestState::Instance());

void MarcoTestState::OnKeyboardEvent(const SDL_KeyboardEvent& k)
{
	if(k.keysym.sym == SDLK_ESCAPE) 
	{
		Engine::TheGame::Instance() ->SetCurrentGameState(nullptr);
	}
	
	float s = 8;

	GameCamera* c = TheGameCamera::Instance();
	
	switch(k.type)
	{
		case SDL_KEYDOWN:
			if(k.keysym.sym == SDLK_w)
				c ->SetVel(c ->GetVel() + Engine::Vec3(0,0,-s));
			if(k.keysym.sym == SDLK_s)
				c ->SetVel(c ->GetVel() + Engine::Vec3(0,0,s));
			if(k.keysym.sym == SDLK_a)
				c ->SetVel(c ->GetVel() + Engine::Vec3(-s,0,0));
			if(k.keysym.sym == SDLK_d)
				c ->SetVel(c ->GetVel() + Engine::Vec3(s,0,0));
			if(k.keysym.sym == SDLK_o)
				c ->SetVel(c ->GetVel() + Engine::Vec3(0,s,0));
			if(k.keysym.sym == SDLK_l)
				c ->SetVel(c ->GetVel() + Engine::Vec3(0,-s,0));

			break;

		case SDL_KEYUP:
			if(k.keysym.sym == SDLK_w)
				c ->SetVel(c ->GetVel() - Engine::Vec3(0,0,-s));
			if(k.keysym.sym == SDLK_s)
				c ->SetVel(c ->GetVel() - Engine::Vec3(0,0,s));
			if(k.keysym.sym == SDLK_a)
				c ->SetVel(c ->GetVel() - Engine::Vec3(-s,0,0));
			if(k.keysym.sym == SDLK_d)
				c ->SetVel(c ->GetVel() - Engine::Vec3(s,0,0));
			if(k.keysym.sym == SDLK_o)
				c ->SetVel(c ->GetVel() - Engine::Vec3(0,s,0));
			if(k.keysym.sym == SDLK_l)
				c ->SetVel(c ->GetVel() - Engine::Vec3(0,-s,0));
	}
}

void MarcoTestState::OnQuit()
{
	Engine::TheGame::Instance() ->SetCurrentGameState(nullptr);
};

void MarcoTestState::CreateWanderer()
{
	m_wanderer.SetPos(Engine::Vec3(20.0f, 0.0f, 20.0f));
	m_wanderer.SetScale(Engine::Vec3(1.0f, 0.5f, 1.0f));
	m_wanderer.SetMaxAcc(15.0f);
	m_wanderer.SetMaxSpeed(35.0f);
	m_wanderer.SetMaxAngularVel(6.0f);
	m_wanderer.SetMaxAngularAcc(1.0f);

	Engine::Wander* wander = new Engine::Wander();
	m_wanderer.AddSteeringBehaviour(Engine::WeightedSteeringBehaviour(wander, 1.0f), nullptr);

	m_wanderer.Initialize();
}

void MarcoTestState::CreateGroup()
{
	for(unsigned int n = 0; n < 5; ++n)
	{
		m_unitArray[n].SetPos(Engine::Vec3(Engine::Random(10.0f) - 6.0f, 0.0f, Engine::Random(10.0f) - 6.0f));
		m_unitArray[n].SetScale(Engine::Vec3(1.0f, 0.5f, 1.0f));
		m_unitArray[n].SetMaxAcc(15.0f);
		m_unitArray[n].SetMaxSpeed(35.0f);
		m_unitArray[n].SetMaxAngularVel(6.0f);
		m_unitArray[n].SetMaxAngularAcc(1.0f);
			  
		Engine::Flock* flock = new Engine::Flock();
		flock ->SetValues(2.0f, 100.0f,//separation
						  4.0f, 100.0f,//cohesion
						   .1f, 100.0f);

		m_unitArray[n].AddSteeringBehaviour(Engine::WeightedSteeringBehaviour(flock, 1.0f), &m_unitArray[n]);

		Engine::CollisionAvoidance* ca = new Engine::CollisionAvoidance();
		ca ->SetTimeBetweenCollisionChecks(.50f);
		
		m_unitArray[n].AddSteeringBehaviour(Engine::WeightedSteeringBehaviour(ca, .4f), &m_unitArray[n]);

		Engine::Pursue* pursue = new Engine::Pursue();
		pursue ->SetMaxPrediction(10.0f);
		
		m_unitArray[n].AddSteeringBehaviour(Engine::WeightedSteeringBehaviour(pursue, 1.0f), &m_wanderer);
		
		Engine::LookWhereYoureGoing* lwyg = new Engine::LookWhereYoureGoing();
		lwyg ->SetSlowRadius(0.5f);
		lwyg ->SetTargetRadius(0.2f);
		lwyg ->SetTimeToTarget(.1f);

		m_unitArray[n].AddSteeringBehaviour(Engine::WeightedSteeringBehaviour(lwyg, 1.0f), &m_unitArray[n]);
			 
		m_unitArray[n].SetGroup(&m_agentGroup);
		m_unitArray[n].Initialize();

		m_agentGroup.AddAgent(&m_unitArray[n]);
	}

	int lol = 0;
}

void MarcoTestState::Activate()
{
	GameState::Activate();
	
	TheGameCamera::Instance()->SetPos(Engine::Vec3(0.0f, 60.0f, 20.0f));
	TheGameCamera::Instance()->SetFoc(Engine::Vec3(0.0f, 0.0f, 0.0f));

	TheWorld::Instance() ->CreateRandom(50, 50, 3.0f, 3.0f, 1);

	CreateWanderer();
	CreateGroup();
}

void MarcoTestState::Deactivate()
{
	GameState::Deactivate();
}

void MarcoTestState::Update()
{
	TheGameCamera::Instance()->Update();

	float wx = m_wanderer.GetPos().x;
	float wz = m_wanderer.GetPos().z;

	Engine::Vec2 o = TheWorld::Instance() ->GetOffset();
	if (wx < -o.x) wx = o.x; 
    else if (wx > o.x) wx = -o.x;
	if (wz < -o.x) wz = o.y; 
    else if (wz > o.y) wz = -o.y;

	m_wanderer.SetPos(Engine::Vec3(wx, 0.0f, wz));

	Engine::TheGame::Instance()->UpdateGameObjects();
}

void MarcoTestState::Draw()
{
	/*
	// Draw grid
    glColor3f(0.8f, 0.8f, 0.8f);
    glBegin(GL_LINES);
    for (int i = -WORLD_SIZE; i <= WORLD_SIZE; i += GRID_SIZE)
	{
        glVertex3i(-WORLD_SIZE, -1, i);
        glVertex3i(WORLD_SIZE, -1, i);

        glVertex3i(i, -1, WORLD_SIZE);
        glVertex3i(i, -1, -WORLD_SIZE);
    }
    glEnd();
	*/

	TheWorld::Instance() ->Draw();

	TheGameCamera::Instance()->Draw();
	Engine::TheGame::Instance()->DrawGameObjects();
} 